<?php
/**
*
* This class for execute the external program of svn
*
* @auth Seven Yang <qineer@gmail.com>
*
*/
class SvnPeer extends CComponent {
	public static $PASS ;
	public static $USER;
	/**
	 * List directory entries in the repository
	 *
	 * @param
	 *        	string a specific project repository path
	 * @return bool true, if validated successfully, otherwise false
	 *        
	 */
	static public function ls($repository) {
		$command = "svn ls " . $repository;
		$output = SvnPeer::runCmd ( $command );
		$output = implode ( "<br>", $output );
		if (strpos ( $output, 'non-existent in that revision' )) {
			return false;
		}
		return "<br>" . $command . "<br>" . $output;
	}
	/**
	 * Duplicate something in working copy or repository, remembering history
	 *
	 * @param
	 *        	$src
	 * @param
	 *        	$dst
	 * @param $comment string
	 *        	specify log message
	 * @return bool true, if copy successfully, otherwise return the error
	 *         message
	 *        
	 * @todo comment need addslashes for svn commit
	 *      
	 */
	static public function copy($src, $dst, $comment) {
		$command = "svn cp $src $dst -m '$comment'";
		$output = SvnPeer::runCmd ( $command );
		$output = implode ( "<br>", $output );
		if (strpos ( $output, 'Committed revision' )) {
			return true;
		}
		return "<br>" . $command . "<br>" . $output;
	}
	/**
	 * Remove files and directories from version control
	 *
	 * @param
	 *        	$url
	 * @return bool true, if delete successfully, otherwise return the error
	 *         message
	 *        
	 * @todo comment need addslashes for svn commit
	 *      
	 */
	static public function delete($url, $comment) {
		$command = "svn del $url -m '$comment'";
		$output = SvnPeer::runCmd ( $command );
		$output = implode ( '<br>', $output );
		if (strpos ( $output, 'Committed revision' )) {
			return true;
		}
		return "<br>" . $command . "<br>" . $output;
	}
	/**
	 * Move and/or rename something in working copy or repository
	 *
	 * @param $src string
	 *        	trunk path
	 * @param $dst string
	 *        	new branch path
	 * @param $comment string
	 *        	specify log message
	 * @return bool true, if move successfully, otherwise return the error
	 *         message
	 *        
	 * @todo comment need addslashes for svn commit
	 *      
	 */
	static public function move($src, $dst, $comment) {
		$command = "svn mv $src $dst -m '$comment'";
		$output = SvnPeer::runCmd ( $command );
		$output = implode ( '<br>', $output );
		if (strpos ( $output, 'Committed revision' )) {
			return true;
		}
		return "<br>" . $command . "<br>" . $output;
	}
	/**
	 * Create a new directory under version control
	 *
	 * @param $url string        	
	 * @param $comment string
	 *        	the svn message
	 * @return bool true, if create successfully, otherwise return the error
	 *         message
	 *        
	 * @todo comment need addslashes for svn commit
	 *      
	 */
	static public function mkdir($url, $comment) {
		$command = "svn mkdir $url -m '$comment'";
		$output = SvnPeer::runCmd ( $command );
		$output = implode ( '<br>', $output );
		if (strpos ( $output, 'Committed revision' )) {
			return true;
		}
		return "<br>" . $command . "<br>" . $output;
	}
	static public function diff($pathA, $pathB) {
		$output = SvnPeer::runCmd ( "svn diff $pathA $pathB" );
		return implode ( '<br>', $output );
	}
	static public function checkout($url, $dir) {
		$command = "cd $dir && svn co $url";
		$output = SvnPeer::runCmd ( $command );
		$output = implode ( '<br>', $output );
		if (strstr ( $output, 'Checked out revision' )) {
			return true;
		}
		return "<br>" . $command . "<br>" . $output;
	}
	static public function update($path) {
		$command = "cd $path && svn up";
		$output = SvnPeer::runCmd ( $command );
		$output = implode ( '<br>', $output );
		preg_match_all ( "/[0-9]+/", $output, $ret );
		if (! $ret [0] [0]) {
			return "<br>" . $command . "<br>" . $output;
		}
		return $ret [0] [0];
	}
	static public function merge($revision, $url, $dir) {
		$command = "cd $dir && svn merge -r1:$revision $url";
		$output = implode ( '<br>', SvnPeer::runCmd ( $command ) );
		if (strstr ( $output, 'Text conflicts' )) {
			return 'Command: ' . $command . '<br>' . $output;
		}
		return true;
	}
	static public function commit($dir, $comment) {
		$command = "cd $dir && svn commit -m '$comment'";
		$output = implode ( '<br>', SvnPeer::runCmd ( $command ) );
		if (strpos ( $output, 'Committed revision' ) || empty ( $output )) {
			return true;
		}
		
		return $output;
	}
	static public function getStatus($dir) {
		$command = "cd $dir && svn st";
		return SvnPeer::runCmd ( $command );
	}
	static public function hasConflict($dir) {
		$output = SvnPeer::getStatus ( $dir );
		foreach ( $output as $line ) {
			if ('C' == substr ( trim ( $line ), 0, 1 ) || ('!' == substr ( trim ( $line ), 0, 1 ))) {
				return true;
			}
		}
		return false;
	}
	/**
	 * Show the log messages for a set of path with XML
	 *
	 * @param
	 *        	path string
	 * @return log message string
	 *        
	 */
	static public function getLog($path) {
		$command = "svn log $path --xml";
		$output = SvnPeer::runCmd ( $command );
		return implode ( '', $output );
	}
	static public function getPathRevision($path) {
		$command = "svn info $path --xml";
		$output = SvnPeer::runCmd ( $command );
		$string = implode ( '', $output );
		$xml = new SimpleXMLElement ( $string );
		foreach ( $xml->entry [0]->attributes () as $key => $value ) {
			if ('revision' == $key) {
				return $value;
			}
		}
	}
	static public function getHeadRevision($path) {
		$command = "cd $path && svn up";
		$output = SvnPeer::runCmd ( $command );
		$output = implode ( '<br>', $output );
		preg_match_all ( "/[0-9]+/", $output, $ret );
		if (! $ret [0] [0]) {
			return "<br>" . $command . "<br>" . $output;
		}
		return $ret [0] [0];
	}
	/**
	 * Run a cmd and return result
	 *
	 * @param
	 *        	string command line
	 * @param
	 *        	boolen true need add the svn authentication
	 * @return array the contents of the output that svn execute
	 *        
	 */
	static protected function runCmd($command) {
		$authCommand = ' --username ' . SvnPeer::$USER . ' --password ' . SvnPeer::$PASS . ' --no-auth-cache --non-interactive --trust-server-cert ';
		exec ( $command . escapeshellcmd($authCommand) . " 2>&1", $output );
		return $output;
	}
	
}

?>